package com.syqc.monitor.ui.text

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import autodispose2.autoDispose
import com.syqc.comlib.UserConstant
import com.syqc.comlib.auto.AutoDisposeViewModel
import com.syqc.comlib.utils.AppContext
import com.syqc.comlib.utils.GsonUtil
import com.syqc.entity.CmdNote
import com.syqc.entity.CmdReply
import com.syqc.entity.SendText
import com.syqc.entity.TextCar
import com.syqc.monitor.R
import com.syqc.net.ServiceHelper
import com.syqc.utils.UrlUtil
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
import io.reactivex.rxjava3.subjects.PublishSubject
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException

/**
 *@Author Jasper
 *@Time   2021/1/9
 *@Desc   文本下发
 */
class TextSendViewModel : AutoDisposeViewModel() {
    var carId = ""
    var urgent = "0"
    var display = "0"
    var tts = "0"
    var adDisplay = "0"
    var textMsg = ""
    var isSend: Boolean = false
    var teamId = ""

    private var subscribe: Disposable? = null
    private val sendSub by lazy { PublishSubject.create<Int>() }
    fun sendObserver(): Observable<Int> = sendSub.hide()

    // 发送单条文本信息
    fun sendTextCmdMsg() {
        if (carId.isEmpty()) {
            toast(R.string.hint_toast_choose_car)
            return
        }
        val signBit = "${urgent}0$display$tts${adDisplay}000"
        if (signBit == "00000000") {
            toast(R.string.hint_toast_send_content_type)
            return
        }
        if (textMsg.isEmpty()) {
            toast(R.string.hint_toast_send_content)
            return
        }
        isSend = true
        sendSub.onNext(R.string.desc_stop_send)
        val textSend = GsonUtil.toJson(SendText(signBit, textMsg)).replace("%", "%25")
        ServiceHelper.getRepository()
            .sendCmd(UserConstant.current_userId, carId, "501", "", textSend)
            .autoDispose(this)
            .subscribe({
                toast(
                    UrlUtil.getCmdToast()[it.rspCode]
                        ?: AppContext.getDescById(R.string.toast_send_faile)
                )
                isSend = false
                sendSub.onNext(R.string.desc_send_cmd)
            }, {
                isSend = false
                toast(it.message ?: "")
                sendSub.onNext(R.string.desc_send_cmd)
            })
    }

    // 停止发送
    fun stopSubscribe() {
        isSend = false
        sendSub.onNext(R.string.desc_send_cmd)
        if (subscribe?.isDisposed == false) subscribe?.dispose()
    }

    val mNoteLive = MutableLiveData<CmdNote>()
    fun cmdNote() {
        toastLoading(true)
        ServiceHelper.getRepository().getCmdNote().autoDispose(this).subscribe({
            toastLoading(false)
            if (it.sysList.isEmpty() && it.userList.isNullOrEmpty()) {
                toast(R.string.desc_toast_no_data)
                return@subscribe
            }
            mNoteLive.postValue(it)
        }, error)
    }

    val testLive = MutableLiveData<Boolean>()
    fun testUrl(url: String) {
        toastLoading(true)
        ServiceHelper.getRepository().testCmdUrl(url).autoDispose(this).subscribe({
            toastLoading(false)
            testLive.postValue(true)
        }, {
            toastLoading(false)
            testLive.postValue(false)
        })
    }

    // 获取车队车辆
    fun getCars() {
        if (!isParamsOk()) return
        toastLoading(true)
        ServiceHelper.getRepository().getCarByTeamId(teamId).autoDispose(this).subscribe({
            toastLoading(false)
            if (isHasListData(it)) return@subscribe
            initCommand(it)
        }, error)
    }

    private fun isParamsOk(): Boolean {
        if (teamId.isEmpty()) {
            toast(R.string.hint_toast_choose_team)
            return false
        }
        val signBit = "${urgent}0$display$tts${adDisplay}000"
        if (signBit == "00000000") {
            toast(R.string.hint_toast_send_content_type)
            return false
        }
        if (textMsg.isEmpty()) {
            toast(R.string.hint_toast_send_content)
            return false
        }
        return true
    }

    // 批量命令处理
    private val executorService = Executors.newFixedThreadPool(10)
    private val disposables = CompositeDisposable()
    private val updateSubjectDisposable = CompositeDisposable() // 单独管理 updateSubject 订阅
    private val commands = mutableListOf<TextCar>()
    private val _carsLive = MutableLiveData<List<TextCar>>()
    val carsLive: LiveData<List<TextCar>> = _carsLive
    private var isClear = false

    // 更新缓冲
    private val updateSubject = PublishSubject.create<List<TextCar>>()

    init {
        updateSubject
            .debounce(200, TimeUnit.MILLISECONDS) // 每200ms提交一次更新
            .autoDispose(this).subscribe {
                _carsLive.postValue(it) }
            .let {
                updateSubjectDisposable.add(it) }
    }

    private fun initCommand(data: List<TextCar>) {
        isClear = false
        commands.clear()
        commands.addAll(data.map { it.copy(state = Status.WAITING) })
        updateSubject.onNext(commands.toList())
        if (!isParamsOk()) return
        val signBit = "${urgent}0$display$tts${adDisplay}000"
        val textSend = GsonUtil.toJson(SendText(signBit, textMsg)).replace("%", "%25")
        executeCommand(textSend)
    }

    private fun executeCommand(content: String) {
        commands.forEachIndexed { index, textCar ->
            if (isClear) return@forEachIndexed
            if (!textCar.online) {
                synchronized(commands) {
                    commands[index] = textCar.copy(state = Status.OFFLINE)
                    updateSubject.onNext(commands.toList())
                }
                return@forEachIndexed
            }

            executorService.submit {
                val disposable = sendCmd(textCar.carId, content)
                    .subscribeOn(Schedulers.io()).autoDispose(this)
                    .subscribe({ reply ->
                        synchronized(commands) {
                            commands[index] = textCar.copy(
                                state = if (reply.rspCode == "0") Status.SUCCESS else Status.FAILURE,
                            )
                            updateSubject.onNext(commands.toList())
                        }
                    }, { error ->
                        synchronized(commands) {
                            commands[index] = textCar.copy(
                                state = when (error) {
                                    is TimeoutException -> Status.TIMEOUT
                                    else -> Status.FAILURE
                                },
                            )
                            updateSubject.onNext(commands.toList())
                        }
                    })
                disposables.add(disposable)
            }
        }
    }

    private fun sendCmd(carId: String, content: String): Single<CmdReply> {
        return ServiceHelper.getRepository()
            .sendCmd(UserConstant.current_userId, carId, "501", "", content)
            .timeout(60, TimeUnit.SECONDS) // 调整为3秒超时
    }

    fun clear() {
        isClear = true
        commands.clear()
        disposables.clear()
    }

    override fun onCleared() {
        super.onCleared()
        clear()
        updateSubjectDisposable.clear()
        executorService.shutdown()
        try {
            if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
                executorService.shutdownNow()
            }
        } catch (e: InterruptedException) {
            executorService.shutdownNow()
        }
    }
}

enum class Status {
    SUCCESS, FAILURE, WAITING, TIMEOUT, OFFLINE
}